package com.fakeDYChat.common.common.aspect;

import com.fakeDYChat.common.common.annotation.RedissonLock;
import com.fakeDYChat.common.common.constant.RedisKey;
import com.fakeDYChat.common.common.service.LockService;
import com.fakeDYChat.common.common.utils.SpElUtils;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Optional;

//order(0)提高优先级，保证锁比事务先执行，避免锁在事务内才执行而导致锁失效
@Order(0)
@Slf4j
@Aspect
@Component
public class RedissonLockAspect {

    private final LockService lockService;

    public RedissonLockAspect(LockService lockService) {
        this.lockService = lockService;
    }

    @Around("@annotation(com.fakeDYChat.common.common.annotation.RedissonLock)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取注解的方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RedissonLock redissonLock = method.getAnnotation(RedissonLock.class);
        String prefix = StringUtil.isBlank(redissonLock.prefixKey()) ? RedisKey.getMethodKey(method) : redissonLock.prefixKey();
        String key = SpElUtils.parseSpEl(method, joinPoint.getArgs(), redissonLock.key());
        return lockService.executeWithLockThrow(prefix + ":" + key, redissonLock.waitTime(), redissonLock.unit(), joinPoint::proceed);
    }
}
